package m.store.service;

import m.base.model.StoreInfo;
import m.base.model.UserInfo;
import m.base.util.PowerUtil;
import m.common.model.util.*;
import m.common.service.Service;
import m.store.model.*;
import m.store.task.AskRemoveSaleSupport;
import m.store.task.GoodsStockRecordSupport;
import m.store.task.GuestSaleSupport;
import m.store.task.MonthRecordSupport;
import m.system.exception.MException;
import m.system.util.*;

import java.sql.SQLException;
import java.util.*;

public class SaleInfoService extends Service {
    private boolean isVerifyStock(String stockType){
        if(StockInfo.Type_Virtual.equals(stockType)) return false;
        else if(StockInfo.Type_Server.equals(stockType)) return false;
        else return true;
    }
    public String save(SaleInfo model, List<GoodsOutRecord> goodsList) throws Exception {
        if(null==goodsList||goodsList.isEmpty()) throw new MException(this.getClass(),"请添加出库商品明细");
        ModelQueryCheck.init(model)
            .checkNotNull("saleDate","出库日期不能为空")
            .checkNotNull("guest.oid","请选择购货客户")
            .checkNotNull("status","状态错误")
            .checkStrEq("status",OrderModel.Status_Register,"登记状态才能修改")
            .doCheck(false,true);
        PowerUtil.verifyAccountDate(model.getSaleDate(),"出库日期");
        if(SaleInfo.Type_Refund.equals(model.getType())){
            if(ObjectUtil.isEmptyOid(model.getRefundStock())) throw new MException(this.getClass(),"参数错误");
        }
        String msg="";
        if(ObjectUtil.isEmptyOid(model)){
            model.setOid(GenerateID.generatePrimaryKey());
            ModelUpdateUtil.insertModel(model);
            msg="保存成功";
        }else{
            ModelUpdateUtil.updateModel(model,"guest.oid","saleDate","remark");
            msg="修改成功";
        }
        ModelUpdateUtil.delete(GoodsOutRecord.class, QueryCondition.eq("sale.oid",model.getOid()));
        for(GoodsOutRecord record : goodsList){
            ModelQueryCheck.init(record)
                .checkNotNull("record.oid","请选择库存商品")
                .checkNotNull("price","请输入单价")
                .checkNumberRange("price",0D,999999999D,"单价不能小于0")
                .checkNotNull("num","请输入数量")
                .checkNumberRange("num",1D,999999999D,"数量不能小于1")
                .checkNotNull("preferential","请输入优惠金额")
                .doCheck(false,true);
            GoodsStockRecord stockRecord=ModelQueryList.getModel(record.getRecord(),"*","goods.*","stock.type");
            record.setOid(GenerateID.generatePrimaryKey());
            record.setGoods(stockRecord.getGoods());
            record.setSale(model);
            record.setStore(model.getStore());
            record.setOperDate(new Date());
            record.setSaleAmount(NumberUtil.round(record.getNum()*record.getPrice()-record.getPreferential(),2));
            record.setPreferentialPrice(NumberUtil.round((record.getNum()*record.getPrice()-record.getPreferential())/record.getNum(),2));
            record.setSurplusNum(record.getNum());
            record.setSurplusAmount(record.getSaleAmount());
            if(isVerifyStock(stockRecord.getStock().getType())) {
                record.setStockPrice(stockRecord.getPreferentialPrice());
                record.setGainAmount(NumberUtil.round((record.getPreferentialPrice()-record.getStockPrice())*record.getNum(),2));
            }else{//虚拟库存的不判断库存
                record.setStockPrice(null);
                record.setGainAmount(null);
            }
        }
        ModelUpdateUtil.insertModels(goodsList.toArray(new GoodsOutRecord[0]));
        updateAmount(model.getOid(),model.getStore().getOid(),model.getGuest().getOid());
        return msg;
    }
    protected void updateAmount(String oid,String storeOid,String guestOid) throws MException {
        boolean noAccount=storeOid.equals(guestOid);
        ModelUpdate.init(SaleInfo.class)
            .set("saleAmount",GoodsOutRecord.class,"ifnull(sum(#{saleAmount}),0)",QueryCondition.eq("sale.oid",oid))
            .setExp("oweAmount",noAccount?"0":"#{saleAmount}-#{incomeAmount}")
            .setExp("incomeStatus",noAccount?"'W'":"'N'")
            .execute(oid);
    }

    /**
     * 提交
     */
    public String saveAndSubmit(SaleInfo model, List<GoodsOutRecord> goodsList,boolean repositoryCheck) throws Exception {
        save(model,goodsList);
        List<GoodsOutRecord> ls=ModelQueryList.getModelList(GoodsOutRecord.class,new String[]{"*","record.stock.type"},null,QueryCondition.eq("sale.oid",model.getOid()));
        List<GoodsOutVirtualStock> vs=new ArrayList<>();
        Map<String,Integer> numMap=new HashMap<>();
        Set<String> error=new HashSet<>();
        for(GoodsOutRecord record : ls){
            GoodsStockRecord stockRecord=ModelQueryList.getModel(record.getRecord(),"*","goods.*","stock.type");
            numMap.merge(stockRecord.getOid(), record.getNum(), Integer::sum);//累加相同商品数量
            if(isVerifyStock(record.getRecord().getStock().getType())) {
                record.setStockPrice(stockRecord.getPreferentialPrice());
                record.setGainAmount(NumberUtil.round((record.getPreferentialPrice()-record.getStockPrice())*record.getNum(),2));
                //校验库存
                if (stockRecord.getSurplusNum() - numMap.get(stockRecord.getOid()) < 0)
                    error.add(stockRecord.getGoods().getName());
            }else{
                if(StockInfo.Type_Virtual.equals(record.getRecord().getStock().getType())) {
                    GoodsOutVirtualStock v = new GoodsOutVirtualStock();
                    v.setOid(GenerateID.generatePrimaryKey());
                    v.setRecord(record);
                    v.setRepository(PowerUtil.getDefRepository());
                    v.setStockNum(record.getNum());
                    v.setPreferential(0d);
                    vs.add(v);
                }
            }
        }
        if(!error.isEmpty()) //存在库存不足
            throw new MException(this.getClass(),"库存不足 - "+ ArrayUtil.connection(error.toArray(),","));
        String msg;
        if(!vs.isEmpty()){
            model.setStatus(OrderModel.Status_Confirm);
            model.setHasVirtualStock(SaleInfo.Has_Yes);
            ModelUpdateUtil.insertModels(vs.toArray(new GoodsOutVirtualStock[0]));
            msg="提交成功，包含虚拟库存，需确认调货信息再次提交。";
        }else{
            model.setStatus(OrderModel.Status_Check);
            if(repositoryCheck) getService(OrderRepositoryCheckService.class).insertCheck(model);
            model.setHasVirtualStock(SaleInfo.Has_No);
            msg="提交成功";
        }
        model.setSubmitDate(new Date());
        ModelUpdateUtil.updateModel(model,"status","hasVirtualStock","submitDate");
        return msg;
    }
    public String saveAndSubmit(SaleInfo model, List<GoodsOutRecord> goodsList) throws Exception {
        return saveAndSubmit(model,goodsList,true);
    }
    public void saveVirtualStock(List<GoodsOutVirtualStock> virtualStocks) throws MException {
        ModelUpdateUtil.updateModels(virtualStocks.toArray(new GoodsOutVirtualStock[0]));
    }
    public void confirm(SaleInfo model,UserInfo user,boolean repositoryCheck) throws Exception {
        ModelQueryCheck.init(model)
            .checkStrEq("status",OrderModel.Status_Confirm,"确认中的才能提交")
            .checkStrEq("inputUser.oid",user.getOid(),"权限错误")
            .doCheck(false,true);
        List<GoodsOutVirtualStock> vs=ModelQueryList.getModelList(GoodsOutVirtualStock.class,new String[]{"*","record.num"},null,
                QueryCondition.eq("record.sale.oid",model.getOid()));
        for(GoodsOutVirtualStock v : vs){
            if(null==v.getPrice()||null==v.getStockNum()) throw new MException(this.getClass(),"调货信息未完善，请确认");
            if(v.getStockNum()<v.getRecord().getNum()) throw new MException(this.getClass(),"调货数量不能低于出货数量，请确认");
        }
        model.setStatus(OrderModel.Status_Check);
        if(repositoryCheck) getService(OrderRepositoryCheckService.class).insertCheck(model);
        model.setSubmitDate(new Date());
        ModelUpdateUtil.updateModel(model,"status","submitDate");
    }
    public void confirm(SaleInfo model,UserInfo user) throws Exception {
        confirm(model,user,true);
    }

    /**
     * 删除
     */
    public void delete(String oid, UserInfo user) throws Exception {
        SaleInfo model=ModelQueryList.getModel(SaleInfo.class,oid,"*");
        ModelQueryCheck.init(model)
            .checkStrEq("status",OrderModel.Status_Register,"登记中才能删除")
            .checkStrEq("inputUser.oid",user.getOid(),"权限错误")
            .doCheck(false,true);
        ModelUpdateUtil.deleteModel(model);
        ModelUpdateUtil.delete(GoodsOutRecord.class, QueryCondition.eq("sale.oid",model.getOid()));
        AskRemoveSaleSupport.add(model.getOid());
        AskRemoveSaleSupport.start();
    }

    /**
     * 审核通过
     */
    public void check(String oid,Date saleDate,String remark, StoreInfo store,UserInfo user) throws Exception {
        getService(OrderRepositoryCheckService.class).verifyCheckOver(oid);
        SaleInfo model=ModelQueryList.getModel(SaleInfo.class,oid,"*");
        model.setSaleDate(saleDate);
        model.setRemark(remark);
        ModelQueryCheck.init(model)
            .checkNotNull("saleDate","出库日期不能为空")
            .checkStrEq("status",OrderModel.Status_Check,"审核中才能通过")
            .checkStrEq("store.oid",store.getOid(),"权限错误")
            .doCheck(false,true);
        PowerUtil.verifyAccountDate(model.getSaleDate(),"出库日期");
        model.setStatus(OrderModel.Status_Done);
        model.setCheckUser(user);
        model.setCheckDate(new Date());
        ModelUpdateUtil.updateModel(model,"status","checkUser.oid","checkDate","saleDate","remark");
        //明细关联
        List<GoodsOutRecord> ls=ModelQueryList.getModelList(GoodsOutRecord.class,new String[]{"*","record.*","record.stock.type","record.goods.*"},null,
                QueryCondition.eq("sale.oid",model.getOid()));
        Set<String> error=new HashSet<>();
        for(GoodsOutRecord record : ls){
            if(StockInfo.Type_Server.equals(record.getRecord().getStock().getType())){
                record.setStockPrice(0d);
                record.setGainAmount(NumberUtil.round((record.getPreferentialPrice()-record.getStockPrice())*record.getNum(),2));
                ModelUpdateUtil.updateModel(record,"stockPrice","gainAmount");
                getService(StoreGoodsService.class).updateServerStockNum(record.getRecord().getGoods().getOid());
            }else if(StockInfo.Type_Virtual.equals(record.getRecord().getStock().getType())
                    ||record.getNum()>record.getRecord().getSurplusNum())
                error.add(record.getRecord().getGoods().getName());
            else if(null==record.getStockPrice()){
                record.setStockPrice(record.getRecord().getPreferentialPrice());
                record.setGainAmount(NumberUtil.round((record.getPreferentialPrice()-record.getStockPrice())*record.getNum(),2));
                ModelUpdateUtil.updateModel(record,"stockPrice","gainAmount");
            }
        }
        if(!error.isEmpty()) //存在库存不足
            throw new MException(this.getClass(),"库存不足 - "+ ArrayUtil.connection(error.toArray(),","));
        //更新商品信息
        ls.forEach(item -> GoodsStockRecordSupport.add(item.getRecord().getOid(), item.getRecord().getStock().getOid(), item.getRecord().getGoods().getOid()));
        GoodsStockRecordSupport.start();
        //更新客户出库金额
        GuestSaleSupport.add(model.getGuest().getOid());
        GuestSaleSupport.start();
        //更新月度统计
        MonthRecordSupport.add(model.getInputUser().getOid(),model.getSaleDate(),MonthRecord.Type_Sale);
        MonthRecordSupport.start();
    }

    /**
     * 退回
     */
    public void refund(String oid, StoreInfo store,UserInfo user) throws Exception {
        SaleInfo model=ModelQueryList.getModel(SaleInfo.class,oid,"*");
        ModelQueryCheck.init(model)
            .checkStrIn("status",new String[]{OrderModel.Status_Check,OrderModel.Status_Confirm},"审核中和确认中的才能退回")
            .checkStrEq("store.oid",store.getOid(),"权限错误")
            .doCheck(false,true);
        model.setStatus(OrderModel.Status_Register);
        model.setCheckUser(user);
        model.setCheckDate(new Date());
        model.setRepositoryStatus(StringUtil.isSpace(model.getRepositoryStatus())?null:OrderRepositoryCheck.Status_No);
        ModelUpdateUtil.updateModel(model,"status","checkUser.oid","checkDate","repositoryStatus");
        ModelUpdateUtil.delete(GoodsOutVirtualStock.class,QueryCondition.eq("record.sale.oid",model.getOid()));
    }
    public void updateInIncomeAmount(String saleOid) throws MException {
        ModelUpdate.init(SaleInfo.class)
            .set("inIncomeAmount", IncomeAmountRecord.class,"ifnull(sum(#{incomeAmount}),0)",
                QueryCondition.eq("sale.oid",saleOid)
            )
            .execute(saleOid);
    }
}
